import { VNode } from 'vue';
import { Component } from 'vue-property-decorator';

import {
  ClientAction,
  isFunction,
  isEnumField,
  getControl,
  getRenderer,
  getBehaviorByKey,
  cacheDynamicEnumOptions,
  getCachedEnumOptions,
} from '../../vendors/handie';
import { EnumFieldOptionGetter, EnumField, MultiEnumField } from '../../vendors/handie/types/input';

import { DataTableProps } from './typing';
import { isActionsAuthorized, resolveAuthorizedActions, resolveTableProps } from './helper';
import ListViewHeadlessWidget from './ListView';

@Component
export default class TableViewHeadlessWidget extends ListViewHeadlessWidget {
  private tableProps: DataTableProps = {} as any;

  protected get searchable(): boolean {
    return !!this.context.getSearch();
  }

  protected get accessible(): Record<string, boolean> | null {
    return (this as any).$store.state.session.authority.accessible;
  }

  protected get topActions(): ClientAction[] {
    return isActionsAuthorized(this.context.getActionsAuthority(), this.accessible)
      ? resolveAuthorizedActions(
          this.context
            .getActions()
            .filter(({ context }) => context && context !== 'single') as ClientAction[],
          this.context.getActionsAuthority(),
          this.accessible,
        )
      : [];
  }

  protected renderSearch(): VNode | null {
    const h = this.$createElement;

    return this.searchable
      ? h('div', { staticClass: 'TableView-search' }, [h(getRenderer('SearchRenderer'))])
      : null;
  }

  protected renderActionBar(): VNode | null {
    const h = this.$createElement;

    return this.topActions.length > 0
      ? h(
          'div',
          { staticClass: 'TableView-tableActions' },
          this.topActions.map(action => h(getRenderer('ActionRenderer'), { props: { action } })),
        )
      : null;
  }

  protected renderDataTable(): VNode {
    return this.$createElement(getControl('DataTable'), {
      props: {
        ...this.tableProps,
        className: 'TableView-dataTable',
        dataSource: this.dataSource,
        currentPage: this.pageNum,
        pageSize: this.pageSize,
        total: this.total,
        pageSizes: this.config.pageSizes || getBehaviorByKey('common.view.listViewPageSizes'),
        loading: this.loading,
      },
      on: {
        'selection-change': selected => this.context.setValue(selected),
        'current-change': currentPage => this.context.setCurrentPage(currentPage),
        'size-change': pageSize => this.context.setPageSize(pageSize),
      },
    });
  }

  private loadTableData(): void {
    const moduleName = this.context.getModuleContext().getModuleName();
    const needCacheDynamicEnumFields = this.fields.filter(
      field =>
        isEnumField(field) &&
        isFunction((field as EnumField | MultiEnumField).options) &&
        !getCachedEnumOptions(moduleName, field),
    );

    // 有动态选项的枚举字段时先发相关 HTTP 请求并将结果缓存，
    // 以避免表格渲染时发出很多相关 HTTP 请求
    if (needCacheDynamicEnumFields.length > 0) {
      Promise.all(
        needCacheDynamicEnumFields.map(field =>
          ((field as EnumField | MultiEnumField).options as EnumFieldOptionGetter)(),
        ),
      ).then(results => {
        results.forEach((result, idx) => {
          if (result.success) {
            cacheDynamicEnumOptions(moduleName, needCacheDynamicEnumFields[idx], result.data);
          }
        });

        this.context.load();
      });
    } else {
      this.context.load();
    }
  }

  protected created(): void {
    this.tableProps = resolveTableProps(this.context, this.accessible);

    const searchContext = this.context.getSearchContext();

    if (searchContext && !searchContext.isReady()) {
      searchContext.on('ready', () => this.loadTableData());
    } else {
      this.loadTableData();
    }
  }
}
